/**
 *  TinyPasswordManager
 *  Copyright (C) 2008 Gross David <gdavid.devel@gmail.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef FIREFOX_PASSWORD_MANAGER_H
#define FIREFOX_PASSWORD_MANAGER_H

#include "exceptions.h"
#include "sqlite3.h"
#include "identifier.h"

#include <string>
#include <vector>

typedef enum {
    siBuffer,
    siClearDataBuffer,
    siCipherDataBuffer,
    siDERCertBuffer,
    siEncodedCertBuffer,
    siDERNameBuffer,
    siEncodedNameBuffer,
    siAsciiNameString,
    siAsciiString,
    siDEROID
} SECItemType;

struct SECItem {
    SECItemType type;
    unsigned char *data;
    unsigned int len;
};

typedef enum {
    SECWouldBlock = -2,
    SECFailure = -1,
    SECSuccess = 0
} SECStatus;

typedef SECStatus (*NSSInit)(const char *);
typedef void *(*PK11GetInternalKeySlot)();
typedef SECStatus (*PK11SDRDecrypt)(SECItem *, SECItem *, void *);
typedef SECStatus (*NSSBase64DecodeBuffer)(void *ptr, SECItem *, const char *, unsigned int);
typedef SECStatus (*PK11Authenticate)(void *, int, void *);
typedef SECStatus (*PK11CheckUserPassword)(void *, const char *);
typedef SECStatus (*NSSShutdown)();
typedef void (*PK11FreeSlot)(void *);

typedef int (*SQLite3_open)(const char *, sqlite3 **);
typedef const char *(*SQLite3_errmsg)(sqlite3 *);
typedef int (*SQLite3_prepare_v2)(sqlite3 *, const char *, int, sqlite3_stmt **, const char **);
typedef int (*SQLite3_step)(sqlite3_stmt *);
typedef int (*SQLite3_finalize)(sqlite3_stmt *);
typedef int (*SQLite3_close)(sqlite3 *);
typedef const unsigned char *(*SQLite3_column_text)(sqlite3_stmt*, int iCol);


/*!
 * \class FirefoxPasswordManager
 * \brief This class allows you to access to the credentials of Firefox.
 *
 * The aim of this class is to open the database signons.sqlite and use PKCS#11 and NSS 
 * libraries to decipher credentials.
 *
 * \author Gross David <gdavid.devel@gmail.com>
 * \date 09/08/2009
 */
 
 class FirefoxPasswordManager {
 public:
    //! Create a FirefoxPasswordManager object.
    FirefoxPasswordManager();
    
    //! Create a FirefoxPasswordManager object.
    /*!
     *  \param pathLibraries the installation directory of Firefox ; this path is only
     *         use in order to find *.dll on Windows
     *
     */
    explicit FirefoxPasswordManager(const std::string &pathLibraries);

    //! Initialize NSS and PKCS#11 API.
    /*!
     *  This method call loadLibraries() before executing NSS and PKCS#11 initialization.
     *  \sa loadLibraries()
     */
    void init()
    throw(ExNSSInternalError, ExLibraryNotFound);
    
    //! Check the firefox's master password.
    /*!
     *  \param password the firefox's master password.
     *  \return true if the password is good, false otherwise.
     */
    bool checkUserPassword(const std::string &password);
    
    //! Get Firefox credentials.
    /*!
     *  \param idents a vector of pointer on Identifier objects.
     */
    void getCredentials(std::vector<Identifier *> &idents)
    throw(ExNSSInternalError, ExSQLiteError);
    
    //! Free NSS and PKCS#11 dynamic buffers.
    void terminate();
    
private:
    //! Load all dynamic libraries (.dll / .so) and get functions' address.
    void loadLibraries()
    throw(ExLibraryNotFound);
    
    //! Decipher a buffer with PKCS#11.
    /*!
     *  \param cipheredBuffer the ciphered buffer.
     *  \return the plaintext buffer.
     */
    std::string decipher(const std::string &cipheredBuffer);
    
    /*!
     *  Some functions of PKCS#11 and NSS libraries we 
     *  must use to decipher the credentials.
     */
    NSSInit m_NSS_Init;
    PK11GetInternalKeySlot m_PK11_GetInternalKeySlot;
    PK11SDRDecrypt m_PK11SDR_Decrypt;
    NSSBase64DecodeBuffer m_NSSBase64_DecodeBuffer;
    PK11Authenticate m_PK11_Authenticate;
    PK11CheckUserPassword m_PK11_CheckUserPassword;
    NSSShutdown m_NSS_Shutdown;
    PK11FreeSlot m_PK11_FreeSlot;
    
    /*!
     *  SQLite functions.
     */
    SQLite3_open m_sqlite3_open;
    SQLite3_errmsg m_sqlite3_errmsg;
    SQLite3_prepare_v2 m_sqlite3_prepare_v2;
    SQLite3_step m_sqlite3_step;
    SQLite3_finalize m_sqlite3_finalize;
    SQLite3_close m_sqlite3_close;
    SQLite3_column_text m_sqlite3_column_text;
    
    //! PKCS#11 Key slot.
    void *m_keySlot;
    
    //! Firefox libraries path.
    std::string m_pathLibraries;
    
    //! signons.sqlite path.
    std::string m_pathSignons;
};

#endif
